package edu.thu.studio.ormdesigner.editor.editpart;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.ManhattanConnectionRouter;
import org.eclipse.draw2d.PolygonDecoration;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gef.editpolicies.ConnectionEndpointEditPolicy;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.ui.PlatformUI;

import edu.thu.studio.ormdesigner.editor.command.UpdateReferencesCommand;
import edu.thu.studio.ormdesigner.editor.dialog.LinkDialog;
import edu.thu.studio.ormdesigner.editor.figure.connection.LineConnection;
import edu.thu.studio.ormdesigner.editor.policy.LinkEditPolicy;
import edu.thu.studio.ormdesigner.model.AbstractModel;
import edu.thu.studio.ormdesigner.model.ORMModel;
import edu.thu.studio.ormdesigner.model.diagram.link.Link;
import edu.thu.studio.ormdesigner.model.diagram.node.TableNode;
import edu.thu.studio.ormdesigner.model.orm.table.Column;
import edu.thu.studio.ormdesigner.model.orm.table.Key;
import edu.thu.studio.ormdesigner.model.orm.table.RefColumn;
import edu.thu.studio.ormdesigner.model.orm.table.RefColumnSet;
import edu.thu.studio.ormdesigner.model.orm.table.Reference;
import edu.thu.studio.ormdesigner.model.orm.table.Table;
import edu.thu.studio.ormdesigner.util.ColorUtils;
import edu.thu.studio.ormdesigner.util.Properties;
import edu.thu.studio.ormdesigner.util.Utils;

public class LinkEditPart extends AbstractConnectionEditPart implements
		PropertyChangeListener {

	private static Logger logger = Logger.getLogger(LinkEditPart.class
			.getName());

	private static final boolean DEBUG = false;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void activate() {
		super.activate();

		AbstractModel model = (AbstractModel) this.getModel();
		model.addPropertyChangeListener(this);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void deactivate() {
		AbstractModel model = (AbstractModel) this.getModel();
		model.removePropertyChangeListener(this);

		super.deactivate();
	}

	public final void propertyChange(PropertyChangeEvent event) {
		try {
			if (DEBUG) {
				logger.log(
						Level.INFO,
						this.getClass().getName() + ":"
								+ event.getPropertyName() + ":"
								+ event.toString());
			}

			this.doPropertyChange(event);

		} catch (Exception e) {
			Utils.showExceptionDialog(e);
		}
	}

	protected void doPropertyChange(PropertyChangeEvent event) {
		if (event.getPropertyName().equals("refreshVisuals")) {
			this.refreshVisuals();
		}
	}

	protected ORMModel getORMModel() {
		return (ORMModel) this.getRoot().getContents().getModel();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected IFigure createFigure() {
		Link link = (Link) this.getModel();

		LineConnection connection = new LineConnection(link);
		connection.setForegroundColor(ColorUtils.CONNECTION_FORCEGROUND_COLOR);
		connection.setLineCap(2);
		connection.setTargetDecoration(new PolygonDecoration());
		connection.setConnectionRouter(new ManhattanConnectionRouter());

		return connection;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void createEditPolicies() {
		this.installEditPolicy(EditPolicy.CONNECTION_ROLE, new LinkEditPolicy());
		this.installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE,
				new ConnectionEndpointEditPolicy());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void performRequest(Request request) {
		Link link = (Link) this.getModel();

		if (request.getType().equals(RequestConstants.REQ_OPEN)) {

			// 获取被建立引用关系的表(主键表)
			TableNode toTableNode = (TableNode) link.getTarget();
			Table toTable = toTableNode.getRefTable();

			// 主键列表
			Map<String, String> keyMap = new HashMap<String, String>();

			Key key = toTable.getKey();
			// 如果主键存在则可以建立外键关系
			if (null != key) {
				if (key.hasColumns()) {
					// 生成主键集合
					List<RefColumn> refColumnList = key.getRefColumns()
							.getObjectList();
					for (RefColumn refColumn : refColumnList) {
						keyMap.put(refColumn.getName(), refColumn.getId());
					}

					// 获取要建立关系的表(外键表)
					TableNode fromTableNode = (TableNode) link.getSource();
					Table fromTable = fromTableNode.getRefTable();

					if (fromTableHasColumns(fromTable)) {
						// 获取referenceId 每条连线唯一
						String referenceId = link.getReferenceId();

						// 关系编辑
						LinkDialog dialog = new LinkDialog(PlatformUI
								.getWorkbench().getActiveWorkbenchWindow()
								.getShell(), keyMap, fromTable, link);
						dialog.setLinkDialog(dialog);

						if (dialog.open() == IDialogConstants.OK_ID) {
							// 返回结果
							List<RefColumn> refColumns = dialog.getResult();
							int count = refColumns.size();
							String code = dialog.getCode();
							String name = dialog.getName();
							String stereotype = dialog.getStereotype();

							if (count == 0) { // 用户可以不设置任何主外键关系
								Reference ref = fromTable.getReferences()
										.getReferenceById(referenceId);
								if (null != ref) {
									fromTable.getReferences().remove(ref);
								}
							} else {

								// 移除当前link所有主外键关系
								for (int i = 0; i < count; i++) {
									Reference ref = fromTable.getReferences()
											.getReferenceById(referenceId);
									if (null != ref) {
										fromTable.getReferences().remove(ref);
									}
								}

								// 构造一个关系引用对象
								Reference reference = new Reference();
								if (null == reference.getRefColumns()) {
									reference.setId(Utils.getUUID());
									reference.setCode(code);
									reference.setName(name);
									reference.setStereotype(stereotype);

									RefColumnSet refColumnSet = new RefColumnSet();
									refColumnSet.setId(Utils.getUUID());
									reference.setRefColumns(refColumnSet);

									link.setReferenceId(reference.getId());
								}

								for (RefColumn refColumn : refColumns) {
									reference.getRefColumns().addObject(
											refColumn);
								}
								fromTable.getReferences().addObject(reference);
							}

							UpdateReferencesCommand command = new UpdateReferencesCommand(
									fromTable, link);
							this.getViewer().getEditDomain().getCommandStack()
									.execute(command);
						}
					} else {
						Utils.showErrorDialog(Properties.error_no_columns);
					}

				} else {
					Utils.showErrorDialog(Properties.error_no_columnkey);
				}

			} else {
				Utils.showErrorDialog(Properties.error_no_columnkey);
			}
		}

		super.performRequest(request);
	}

	@Override
	final public void refreshVisuals() {
		super.refreshVisuals();
		LineConnection figure = (LineConnection) this.getFigure();
		figure.refreshLabel();
	}

	public boolean fromTableHasColumns(Table fromTable) {
		List<Column> columns = fromTable.getColumns().getObjectList();

		return columns.size() > 0 ? true : false;
	}

}
